﻿///////////////////////////////////////////////////////////////////////////////
//
// This file is part of the BassDrop project
//   https://code.google.com/p/bass-drop/
//
//
// Creator:	Gergely Krajcsovszki (krajcsovszkig@hotmail.com)
// Date:	2013-07-27 13:15
//
//
// Copyright © 2013-2014. Gergely Krajcsovszki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using BassDrop.Core.Common.Localization;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using BassDrop.Core.Common.Data.IO.Portable;
using BassDrop.Core.Common.Services;
using System.ComponentModel;

namespace BassDrop.Core.Common.Data
{
	/// <summary>
	/// An object that is persisted in some kind of file
	/// </summary>
	/// <typeparam name="T">the type of the represented object</typeparam>
	public abstract class FileObjectBase<T> : INotifyPropertyChanged
	{
		private T m_representedObject;

		/// <summary>
		/// The object represented by this file
		/// </summary>
		public T RepresentedObject
		{
			get
			{
				return m_representedObject;
			}

			protected set
			{
				if ( m_representedObject == null || !m_representedObject.Equals( value ) )
				{
					var temp = m_representedObject;
					m_representedObject = value;
					RepresentedObjectChanged( temp, m_representedObject );
					OnPropertyChanged( new PropertyChangedEventArgs( "RepresentedObject" ) );
				}
			}
		}

		private Uri m_filePath;

		/// <summary>
		/// The path of the designated file of this object in the system
		/// </summary>
		public Uri FilePath
		{
			get
			{
				return m_filePath;
			}

			private set
			{
				if ( m_filePath != value )
				{
					m_filePath = value;
					OnPropertyChanged( new PropertyChangedEventArgs( "FilePath" ) );
				}
			}
		}

		private Exception m_error;

		/// <summary>
		/// The last error that occured while managing this file or null if none occured yet
		/// </summary>
		public Exception Error // TODO: írja ki valahol
		{
			get
			{
				return m_error;
			}

			protected set
			{
				if ( m_error != value )
				{
					m_error = value;
					OnPropertyChanged( new PropertyChangedEventArgs( "Error" ) );
				}
			}
		}

		/// <summary>
		/// Call this from subclasses to set the path to the designated file of the object
		/// </summary>
		/// <param name="representedObject">the initial state of the represented object (or null)</param>
		/// <param name="filePath">the path of the designated file of this object in the system</param>
		protected FileObjectBase( ref T representedObject, Uri filePath )
		{
			RepresentedObject = representedObject;
			FilePath = filePath;
		}

		/// <summary>
		/// Loads the contents of the object from its designated file
		/// </summary>
		public abstract void Load();

		/// <summary>
		/// Saves the contents of the object into its designated file
		/// </summary>
		public abstract void Save();

		/// <summary>
		/// Returns if the local file exists
		/// </summary>
		/// <returns></returns>
		public bool LocalFileExists()
		{
			return ServiceCenter.FileHandler.Exists( FilePath.LocalPath );
		}

		/// <summary>
		/// Moves the designated file of this object. Closes it if it was open.
		/// Overwriting existing files is not allowed.
		/// </summary>
		/// <param name="targetPath">The path where it will be moved to.</param>
		protected void MoveFile( Uri targetPath )
		{
			if ( ServiceCenter.FileHandler.Exists( targetPath.LocalPath ) )
			{
				throw new IOException( Strings.ExceptionMoveTargetExists );
			}

			if ( ServiceCenter.FileHandler.Exists( FilePath.LocalPath ) )
			{
				ServiceCenter.FileHandler.Move( FilePath.LocalPath, targetPath.LocalPath );
			}

			FilePath = targetPath;
		}

		/// <summary>
		/// Called when the RepresentedObject has changed
		/// </summary>
		/// <param name="oldValue">the old value of the RepresentedObject</param>
		/// <param name="newValue">the new value of the RepresentedObject</param>
		protected virtual void RepresentedObjectChanged( T oldValue, T newValue )
		{
		}

		#region INotifyPropertyChanged Members

		/// <summary>
		/// Event fired when the value of one of the properties of this object change
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;

		#endregion

		/// <summary>
		/// Fires a new PropertyChanged event
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnPropertyChanged( PropertyChangedEventArgs e )
		{
			if ( PropertyChanged != null )
			{
				PropertyChanged( this, e );
			}
		}
	}
}
